package yxy.banana.socket.controlled;

import yxy.apple.protobuf.Message.Parcal;
import yxy.banana.socket.ParcalUtility;
import yxy.banana.socket.controlled.Controller.DroppedReason;
import yxy.banana.socket.handler.ParcalHandler;
import yxy.banana.socket.receiver.Observer;

/**
 * 将handler的处理划分为两个走向，除业务消息外的其他处理由controller完成
 */
public abstract class ControlledHandler extends ParcalHandler {

	private Controller<?> controller = null;
	private int channel = 0;

	@Override
	protected void receive(Parcal message) throws Exception {
		if (message.getVersion() == yxy.apple.protobuf.Constants.Version) {
			if (!Observer.shared.detect(message)) {// 先过一下观察者
				if (ParcalUtility.controlling(message)) {
					if (!this.controller.control(message)) {
						this.controller.drop(message, DroppedReason.Unnoticed);
					}
				} else {
					if (!this.business(message)) {
						this.controller.drop(message, DroppedReason.Unnoticed);
					}
				}
			}
		} else {
			this.controller.drop(message, DroppedReason.BadVersion);
		}
	}

	protected abstract boolean business(Parcal message) throws Exception;

	/*
	 * **************************************** 回调Controller ********************************************
	 */
	@Override
	@Deprecated
	protected final void drop(Object message) {
		this.controller.drop(message, DroppedReason.BadFormat);
	}

	@Override
	protected void opened() throws Exception {
		Controller<? extends ControlledHandler> controller = this.controller;
		if (controller != null) {
			this.controller.open();
		} else {
			throw new RuntimeException("Can not find any controller for this handler");
		}
	}

	@Override
	protected void actived() throws Exception {
		this.controller.active();
	}

	@Override
	protected void inactived() throws Exception {
		this.controller.inactive();
	}

	@Override
	protected void closed() throws Exception {
		this.controller.close();
		this.controller = null;
	}

	@Override
	protected void triggered(Object event) throws Exception {
		this.controller.trigger(event);
	}

	@Override
	protected void thrown(Throwable cause) {
		this.controller.caught(cause);
	}

	@Override
	public int channel() {
		return this.channel;
	}

	public Controller<?> controller() {
		return this.controller;
	}

	void setChannel(int channel) {
		this.channel = channel;
	}

	void setController(Controller<?> controller) {
		this.controller = controller;
	}

}
